package com.web.logindemo.aspectj;

import com.web.logindemo.common.annotation.DataScope;
import com.web.logindemo.common.util.SecurityUtils;
import com.web.logindemo.common.util.StringUtils;
import com.web.logindemo.domain.BaseEntity;
import com.web.logindemo.domain.entity.SysRole;
import com.web.logindemo.domain.entity.SysUser;
import com.web.logindemo.domain.model.LoginUser;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

/**
 * 数据权限处理
 */
@Aspect
@Component
public class DataScopeAspect {
    /**
     * 全部数据权限
     */
    public static final String DATA_SCOPE_ALL = "1";

    /**
     * 自定义数据权限
     */
    public static final String DATA_SCOPE_CUSTOM = "2";

    /**
     * 部门数据权限
     */
    public static final String DATA_SCOPE_DEPT = "3";

    /**
     * 部门及子部门数据权限
     */
    public static final String DATA_SCOPE_DEPT_AND_CHILD = "4";

    /**
     * 仅本人数据权限
     */
    public static final String DATA_SCOPE_SELF = "5";


    /**
     * 数据权限过滤关键字
     */
    public static final String DATA_SCOPE = "data_scope";

    // 配置织入点
    @Pointcut("@annotation(com.web.logindemo.common.annotation.DataScope)")
    public void dataScopePointCut() {

    }

    @Before("dataScopePointCut()")
    public void doBefore(JoinPoint joinPoint) {
        clearDataScope(joinPoint);
        handleDataScope(joinPoint);
    }

    private void handleDataScope(JoinPoint joinPoint) {
        // 获得注解
        DataScope dataScope = getAnnotationLog(joinPoint);
        if (dataScope == null) {
            return;
        }
        // 获取当前用户
        LoginUser loginUser = SecurityUtils.getLoginUser();
        if (StringUtils.isNotNull(loginUser)) {
            SysUser currentUser = loginUser.getUser();
            if (StringUtils.isNotNull(currentUser) && !currentUser.isAdmin()) {
                dataScopeFilter(joinPoint, currentUser, dataScope.deptAlias(), dataScope.userAlias());
            }
        }
    }

    /**
     * 数据范围过滤
     * @param joinPoint
     * @param user
     * @param deptAlias
     * @param userAlias
     */
    private void dataScopeFilter(JoinPoint joinPoint, SysUser user, String deptAlias, String userAlias) {
        StringBuilder sqlString = new StringBuilder();

        for(SysRole role: user.getRoles()){
            String dataScope = role.getDataScope();
            if (DATA_SCOPE_ALL.equals(dataScope)) {
                sqlString = new StringBuilder();
                return;
            }
            else if(DATA_SCOPE_CUSTOM.equals(dataScope)){
                sqlString.append(StringUtils.format(
                        "OR {}.dept_id IN (select dept_id from sys_role_dept where role_id = {})",
                        deptAlias, role.getRoleId()
                ));
            }
            else if(DATA_SCOPE_DEPT.equals(dataScope)){
                sqlString.append(StringUtils.format(
                        "OR {}.dept_id = {}", deptAlias, user.getDeptId()
                ));
            }else if(DATA_SCOPE_DEPT_AND_CHILD.equals(dataScope)){
                sqlString.append(StringUtils.format(
                        "OR {}.dept_id IN (select dept_id from sys_dept where dept_id = () or find_id_set( {}, ancestors))",
                        deptAlias, user.getDeptId(), user.getDeptId()
                ));
            }else if(DATA_SCOPE_SELF.equals(dataScope)){
                if(StringUtils.isNotNull(userAlias)){
                    sqlString.append(StringUtils.format(
                            "OR {}.user_id = {}", userAlias, user.getUserId()
                    ));
                }else{
                    sqlString.append("OR 0=1");
                }
            }
        }

        if(StringUtils.isNotNull(sqlString.toString())){
            Object params = joinPoint.getArgs()[0];
            if(StringUtils.isNotNull(params) && params instanceof BaseEntity){
                BaseEntity baseEntity = (BaseEntity) params;
                baseEntity.getParams().put(DATA_SCOPE, "AND ("+sqlString.substring(3)+")");
            }
        }
    }

    private DataScope getAnnotationLog(JoinPoint joinPoint) {
        Signature signature = joinPoint.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        Method method = methodSignature.getMethod();

        if (method != null) {
            return method.getAnnotation(DataScope.class);
        }
        return null;
    }

    private void clearDataScope(JoinPoint joinPoint) {
        Object params = joinPoint.getArgs()[0];
        if (StringUtils.isNotNull(params) && params instanceof BaseEntity) {
            BaseEntity baseEntity = (BaseEntity) params;
            baseEntity.getParams().put(DATA_SCOPE, "");
        }
    }
}
